package scfg.utils.training_set_filter;

import java.io.File;
import java.util.*;

import scfg.AlignedSequence;
import scfg.RNAStatsObj;
import scfg.RnaAlgoPrediction;
import scfg.output.Display;
import scfg.output.RNAFormattedFile;
import scfg.output.database.CtFileAggregator;
import scfg.output.database.DatabaseHandler;
import scfg.output.flot.flot;
import scfg.utils.MFEDensityAppender;

public class Main {
	
//	public static String RNA_DIRECTORY = "/home/david/Documents/RNA/rna_files/approved_ct_files/";
	public static String RNA_DIRECTORY = "/home/david/Documents/RNA/rna_formatted/";

	private static List<AlignedSequence> getAllSequences(String rnaClass) {
		return DatabaseHandler.getAlignedSequenceByRNAClass(rnaClass);
	}
	
	private static void setupDensity(List<AlignedSequence> approved, String rnaClass) {
		for (AlignedSequence seq : approved) {
			String filename = RNA_DIRECTORY + rnaClass + "/" + seq.getName() + ".rna";
//			RNAFormattedFile rnaff = new RNAFormattedFile(filename);
			RNAStatsObj stats = MFEDensityAppender.getRNAStatsObject(filename);
			if (stats == null)
				System.err.println("GTFold Prediction Error: " + seq.getName());
			else {
				boolean update = false;
				if (seq.getStructure("mfe_GTFoldX") == null) {
					seq.addStructure(new RnaAlgoPrediction("mfe_GTFoldX", stats.getPredXStructure()));
					update = true;
				}
				if (seq.getStructure("mfe_GTFold") == null) {
					seq.addStructure(new RnaAlgoPrediction("mfe_GTFold", stats.getPredStructure()));
					update = true;
				}
				if (seq.getStructure("mfe_gt") == null) {
					RNAFormattedFile rnaff = new RNAFormattedFile(new File(filename));
					seq.addStructure(new RnaAlgoPrediction("mfe_gt", rnaff.get("mfe_gt")));
					update = true;
				}
				double denseComp = stats.getMFEDensityX();
				if (seq.getDenseCompString().equals("NULL")) {
					seq.setDenseComp(denseComp);
					update = true;
				}
				if (update){
					DatabaseHandler.updateAlignedSequence(seq);
					DatabaseHandler.updatePredictions(seq);
				}
			}
		}
	}

	public static boolean fillDatabase() {
		try {
			CtFileAggregator.main(new String[1]);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	public static List<AlignedSequence> getApprovedSequences(String rnaClass,
			double densityThreshold, double identityThreshold, Display output) {

		List<AlignedSequence> sequences = getAllSequences(rnaClass);
		System.out.println("Total: " + sequences.size());
		output.outC("Training Set: ").out(rnaClass);
		output.outC("\tStarting With: ").out(sequences.size() + "");
		List<AlignedSequence> approved = AmbiguousFilter
				.getAmbiguousFilteredGroup(sequences);
		output.outC("\tAfter Ambiguous Filtering: ").out(approved.size() + "");
		setupDensity(approved, rnaClass);
		approved = AlignmentFilter.getAlignmentFilteredGroup(approved);
		output.outC("\tAfter Alignment Filtering: ").out(approved.size() + "");
		approved = DensityFilter.getDensityFilteredGroup(approved, 1,
				densityThreshold);
		output.outC("\tAfter Density Filtering: ").out(approved.size() + "");
		approved = IdenityFilter.getIdentityFilteredGroupFromAlignment(approved,
				identityThreshold, false, new Display(rnaClass + "_rejected.txt", null, false));
		output.outC("\tAfter Identity Filtering: ").out(approved.size() + "").finalizeDisplay();
		return approved;
	}
	
	public static List<AlignedSequence>[] getFilteredEMHSet(String rnaClass,
			double densityThreshold, double identityThreshold, Display output) {

		List<AlignedSequence> sequences = getAllSequences(rnaClass);
		System.out.println("Total: " + sequences.size());
		output.outC("Training Set: ").out(rnaClass);
		output.outC("\tStarting With: ").out(sequences.size() + "");
		List<AlignedSequence> approved = AmbiguousFilter
				.getAmbiguousFilteredGroup(sequences);
		output.outC("\tAfter Ambiguous Filtering: ").out(approved.size() + "");
		setupDensity(approved, rnaClass);
		approved = AlignmentFilter.getAlignmentFilteredGroup(approved);
		output.outC("\tAfter Alignment Filtering: ").out(approved.size() + "");
		approved = DensityFilter.getDensityFilteredGroup(approved, 1,
				densityThreshold);
		output.outC("\tAfter Density Filtering: ").out(approved.size() + "");
		List<AlignedSequence>[] approvedSets = RandomizedSetSelector.getEMHTrainingSets(approved);
		for(int i=0;i<3;i++)
			approvedSets[i] = IdenityFilter.getIdentityFilteredGroupFromAlignment(approvedSets[i], 
					identityThreshold, false, new Display("rejected/"+rnaClass + "_rejected_"+(i==0?"easy":i==1?"medium":"hard")+".txt", null, false));
		return approvedSets;
	}

	public static List<List<AlignedSequence>>[] getApprovedSets(String rnaClass,
			double densityThreshold, double identityThreshold, Display output) {
		List<AlignedSequence>[] approvedSets = getFilteredEMHSet(rnaClass, densityThreshold, identityThreshold, output);
		for(int i=0;i<3;i++)
			approvedSets[i] = IdenityFilter.getIdentityFilteredGroupFromAlignment(approvedSets[i], 
					identityThreshold, false, new Display("rejected/"+rnaClass + "_rejected_"+(i==0?"easy":i==1?"medium":"hard")+".txt", null, false));
		List<List<AlignedSequence>>[] approvedRandomSets = (List<List<AlignedSequence>>[]) new ArrayList[3];
		for (int i=0;i<3;i++)
			approvedRandomSets[i] = RandomizedSetSelector.getRandomApprovedSet(approvedSets[i], 5, 50, 0, approvedSets[i].size()-1);
		int totalLeft = approvedSets[0].size() + approvedSets[1].size() + approvedSets[2].size();
		output.outC("\tAfter Identity Filtering: ").out(totalLeft + "").finalizeDisplay();
		return approvedRandomSets;
	}
	
	private static void printTrainingSets(List<List<AlignedSequence>>[] trainingSetsList, String header, boolean singleFile) {
		if (trainingSetsList == null || header == null)
			return;
		String[] arr = new String[] { "_easy", "_medium", "_hard" };
		Display output = new Display(header + ".txt",null,false);
		for (int i=0;i<arr.length;i++) {
			if (trainingSetsList[i] != null) {
				if (!singleFile){
					output.finalizeDisplay();
					output = new Display(header+arr[i]+".txt", null, false);
				}
				printTrainingSets(trainingSetsList[i], output, header+arr[i]);
			}
		}
		output.finalizeDisplay();
	}
	
	private static void printTrainingSets(List<List<AlignedSequence>> trainingSets, Display output, String header) {
		if (trainingSets == null || output == null || header == null)
			return;
		int count = 0;
		for (List<AlignedSequence> set : trainingSets) {
			if (set != null) {
				output.outC("\n>").outC(header).out(" " + (++count));
				for (AlignedSequence seq : set) {
					output.out(seq.getName());
				}
			}
		}
	}
	
	private static void printCompeteTrainingSets(List<AlignedSequence>[] trainingSets, String header) {
		if (trainingSets == null || header == null)
			return;
		String[] diff = { "easy", "medium", "hard" };
		for (int i=0;i<trainingSets.length;i++) {
			Display output = new Display("predictionTrainingSets/" + header + diff[i], null, false);
			for (AlignedSequence seq : trainingSets[i]) {
				String[] arr = seq.getName().split("/");
				output.outC("RNA/rna_formatted/").outC(header).outC("/").outC(arr[arr.length-1]).out(".rna");
			}
			output.finalizeDisplay();
		}
	}
	
	public static AlignedSequence doRun(String RNASet, double densityThreshold, double idenityThreshold, boolean printTrainingSets) {
			System.out.println(Display.box("  " + RNASet + "  ", "\t"));
			
			// Get filtered lists
			List<AlignedSequence> approved = null;
//			approved = getApprovedSequences(RNASet, densityThreshold, idenityThreshold, new Display("dat/" + RNASet+"_filteringResults.txt", null, false));
			/*
			 * Filtering Plots
			 */
//			// select random sets: DON'T USE THE TOP ONE!!
//			List<List<AlignedSequence>>[] approved_sets = RandomizedSetSelector.getMultipleTrainingSets(approved, 5, 50);
			List<List<AlignedSequence>>[] approved_sets = getApprovedSets(RNASet, densityThreshold, idenityThreshold, new Display("dat/" + RNASet+"_filteringResults.txt", null, true));
//			
//			// 3d Knudsen-Hein Productions
//			CustomPlotAnalysis.plot3DKHProductions(approved_sets, "dat/" + RNASet + "_khProductions.dat");
//			
//			// 2d Canonical Base Pair Ratio
//			CustomPlotAnalysis.plotConnocialProportionRatio(approved_sets, "dat/" + RNASet + "_2dBpRatio.dat");
//			
//			// 3d W.C., Wobble and NonCanonical Basepair Ratios
//			CustomPlotAnalysis.plotBasepairProportionRatio(approved_sets, "dat/" + RNASet + "_3DBpRatio.dat");
//			CustomPlotAnalysis.printCFGCountRelationship(approved_sets, RNASet + " ");
//			CustomPlotAnalysis.printCFGCountRelationship2(approved_sets, RNASet + " ");
			
			// Nucleotide proportions
			

			
			/*
			 * Density and Identity plots
			 */
//			CustomPlotAnalysis.densityFmeasureComparison(getAllSequences(RNASet), new Display("dat/"+rnaClass + "DENvsFM.txt", null, false));
//			CustomPlotAnalysis.plotPercentIdentityFMeasureComparison(getAllSequences(RNASet), "dat/" + RNASet + "_identityFMeasurePlot.dat", idenityThreshold);
			
			
			/*
			 * Flot
			 */
//			String htmlFileName = flot.HTML_DIR+"FmComp/"+RNASet+"_FmComp.html";
//			CustomPlotAnalysis.flotPercentIdentityFMeasureComparison(getAllSequences(RNASet), htmlFileName, htmlFileName.replace(".html", ".js"), idenityThreshold);
//			htmlFileName = flot.HTML_DIR+"GrammarParams/"+RNASet+"_GrammarParams.html";
//			printTrainingSets = true;
//			CustomPlotAnalysis.flotGrammarProbabilities(approved_sets, htmlFileName, htmlFileName.replace(".html", ".js"), "Pfold Grammar Probabilities Interactive Graph");
			
			
			/*
			 * Ggobi XML
			 */
//			CustomPlotAnalysis.outputGgobiXMLGrammar(approved_sets, new Display("ggobiXML/" + RNASet + "_KHparams.xml", null, false));
//			CustomPlotAnalysis.outputGgobiXMLNuc(approved_sets, new Display("ggobiXML/" + RNASet + "_NucDist.xml", null, false));
			
			/*
			 * Prediction Plots
			 */
//			List<AlignedSequence>[] arr = RandomizedSetSelector.getEMGTrainingSets(_5S);
//			for(int i =0;i<arr.length;i++)
//				for(AlignedSequence seq : arr[i])
//					System.out.println(seq.getName());
//			CustomPlotAnalysis.generatePredictionPlot(arr, "5S_predictions.dat");
			
			/*
			 * Custom Plots
			 */
			CustomPlotAnalysis.printQuickResults(RandomizedSetSelector.getEMHTrainingSets(getAllSequences(RNASet)));
			
			if (printTrainingSets) {
//				printTrainingSets(approved_sets, RNASet + "_trainingSets", false);
//				printCompeteTrainingSets(getFilteredEMHSet(RNASet, densityThreshold, idenityThreshold, new Display("delete.txt")), RNASet);
			}
			
			return approved == null ? null : approved.get(0);
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO: Command line
		
		// Set up
//		fillDatabase();
		
		boolean my5S = true;
		boolean my16S = true;
		boolean my23S = false;
		boolean printTrainingSets = true;
		boolean countsAndUnion = false;
		
		List<AlignedSequence> seqs = new LinkedList<AlignedSequence>();

		if (my5S)
			seqs.add(doRun("5S", 0.85, 0.8, printTrainingSets));
		if (my16S)
			seqs.add(doRun("16S", 0.87, 0.8, printTrainingSets));
		if (my23S)
			seqs.add(doRun("23S", 0.85, 0.8, printTrainingSets));		
		
		if (countsAndUnion)
			CustomPlotAnalysis.printCountsAndUnion(seqs, new Display("CountsAndUnion.txt", null, true));
		
		System.out.println("\n\n" + Display.box(" Done ", ""));
	}
}
